---
    title: '简单的网格材质'
---

## THREE.MeshBasicMaterial

MeshBasicMaterial是一种非常简单的材质，这种材质不考虑场景中光照的影响。使用这种材质的网格会被渲染成简单的平面多边形，而且也可以显示几何体的线框。

import { Scene } from './02a-basic-mesh-material.jsx';

<Scene />

<br/>

|名称|描述|
|---|---|
|color|设置材质的颜色|
|wireframe|是否显示线框。显示线框对于调试有帮助|
|Wireframelinewidth|线框的线条宽度|
|wireframeLinecap|这个属性定义了线框模式下顶点间线段的端点如何显示.WebGLRenderer对象不支持改属性|
|wireframeLinejoin|这个属性定义了线段连接点如何显示.WebGLRenderer对象不支持改属性|

创建一个网格标准材质很简单,我们可以使用右上角的菜单来控制渲染效果.

```jsx title='chapter-04/02a-basic-mesh-material.jsx'
var meshMaterial = new THREE.MeshBasicMaterial({color: 0x7777ff});
```

在这个例子中有一个side属性.在plane网格可以看到到起作用,材质通常应用在物体前面的面上,所有在平面旋转的时候有一半时间是看不见他的.如果将side设置double,那么几何体两面都有材质.
但是渲染器也会付出更大的工作.

## THREE.MeshDepthMaterial

使用这种材质的物体，其外观不是由光照或某个材质属性决定的，而是由物体到摄像机的距离决定的。
可以将这种材质与其他材质结合使用，从而很容易地创建出逐渐消失的效果。

距离是基于相机的near和far值,距离near越近颜色越白,离相机的far约近约黑. 同时如果对象不在near和far之前的平面内,不会被渲染出来.

import { Scene as SceneB } from './02b-depth-material.jsx';

<SceneB />

<br/>

near 和 far之间的大小决定了场景中物体的亮度和消失速度,如果之间的差值比较大,那么物体消失也会慢点.如果之间的差值比较小,物体的消失比较明显.

创建 MeshDepthMaterial 非常简单, 但是要记住,在render的时候要更新相机.

```jsx title='chapter-04/02b-depth-material.jsx'
scene.overrideMaterial = new THREE.MeshDepthMaterial();
...
function render() {
    ...
    camera.updateProjectionMatrix();
    // render using requestAnimationFrame
    requestAnimationFrame(render);
    renderer.render(scene, camera);
}
```

## 联合材质

THREE.MeshDepthMaterial 是没有颜色的属性的,如果要加给MeshDepthMaterial添加颜色,就要使用MeshBasicMaterial添加颜色,并且将两个材质合并在一起.

import { Scene as SceneC } from './02c-combined-material.jsx';

<SceneC />

<br/>

```jsx title='chapter-04/02c-combined-material.jsx'
import * as SceneUtils  from "three/examples/jsm/utils/SceneUtils";
...
var cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);

var cubeMaterial = new THREE.MeshDepthMaterial();
var colorMaterial = new THREE.MeshBasicMaterial({
    color: controls.color,
    //transparent: true,
    blending: THREE.MultiplyBlending
});
var cube = SceneUtils.createMultiMaterialObject(cubeGeometry, [colorMaterial, cubeMaterial]);
//cube.children[1].scale.set(0.99, 0.99, 0.99);
```
首先创建了两种材质,对于 MeshDepthMaterial 没有什么做的, 对于 MeshBasicMaterial 我们设置了颜色和融合模式,
设置了融合属性之后就会和背景相互作用,这里的背景就是 MeshDepthMaterial. 使用 MultiplyBlending 对象,这种模式会把前景色和背景色.

最后调用THREE.SceneUtils.createMultiMaterialObject()方法创建一个网格的时候，几何体会被复制，返回一个网格组，里面的两个网格完全相同。


## THREE.MeshNormalMaterial

这个材质的每个网格面渲染的颜色都稍微有所不同, 而且在物体旋转的时候,这些颜色也基本保持在原来的位置上.
之所以会这样，是因为每一面的颜色是由从该面向外指的法向量计算得到的。所谓法向量是指与面垂直的向量。

可以将旋转的对象选择为球体(sphere),并且将flatshading属性设置成true. 查看效果比比较明显.
球体上每个三角面上面的箭头就是这个面的法向量.由于球体每个三角面的法向量都不同所以我们得到了一个色彩斑斓的球体.

import { Scene as SceneD } from './02d-mesh-normal-material.jsx';

<SceneD />

<br/>

创建一个MeshNormalMaterial很简单, 其中它有个shading属性,我们可以通过它告诉Three.js如何渲染物体,常见的wireframe和wireframeLinewidth我们前面已经介绍了.
如果使用THREE.FlatShading，那么每个面是什么颜色就渲染成什么颜色，或者也可以使用THREE.SmoothShading，这样就可以使物体的表面变得更光滑。

```jsx 
var meshMaterial = new THREE.MeshNormalMaterial();
```

下面代码展示了如何添加每个三角面的法向量.我们从bufferGeometry中的index序列中获取每个三角面顶点的序号.
再从position属性中按照序号将Vertex3顶点获取到. 然后创建一个THREE.Triangle来代表一个三角面.

```jsx title='chapter-04/02d-mesh-normal-material.jsx'
let position = sphere.geometry.getAttribute('position');
let index = sphere.geometry.index;

let tri = new THREE.Triangle(); // for re-use
let a = new THREE.Vector3(), 
    b = new THREE.Vector3(), 
    c = new THREE.Vector3(); // for re-use


for( let f = 0; f < index.count / 3; f++ ){
    let idxBase = f * 3;
    a.fromBufferAttribute( position, index.getX( idxBase + 0 ) );
    b.fromBufferAttribute( position, index.getX( idxBase + 1 ) );
    c.fromBufferAttribute( position, index.getX( idxBase + 2 ) );
    tri.set( a, b, c );

    let dir = new THREE.Vector3();
    let origin = new THREE.Vector3();

    tri.getNormal(dir);
    tri.getMidpoint(origin);

    var arrow = new THREE.ArrowHelper(
            dir,
            origin,
            2,
            0x3333FF,
            0.5,
            0.5);

    sphere.add(arrow);

}
```


## 在简单几何体上使用多种材质

该案例是一个魔方的,3*3 共9个小立方体组成.

import { Scene as SceneE } from './02e-mesh-face-material.jsx';

<SceneE />

<br/>

我们先创建了一个THREE.Mesh对象,他将保存所有方块.接下来为每个面创建一个材质,并把它们保存在mats数组里面.
记住小方块的位置是基于group的位置,如果group发生了移动或者旋转,所有的小方块都会执行相同的动作.


```jsx title='chapter-04/02e-mesh-face-material.jsx'
var group = new THREE.Mesh();
// add all the rubik cube elements
var mats = [];
mats.push(new THREE.MeshBasicMaterial({color: 0x009e60}));
mats.push(new THREE.MeshBasicMaterial({color: 0x0051ba}));
mats.push(new THREE.MeshBasicMaterial({color: 0xffd500}));
mats.push(new THREE.MeshBasicMaterial({color: 0xff5800}));
mats.push(new THREE.MeshBasicMaterial({color: 0xC41E3A}));
mats.push(new THREE.MeshBasicMaterial({color: 0xffffff}));

for (var x = 0; x < 3; x++) {
    for (var y = 0; y < 3; y++) {
        for (var z = 0; z < 3; z++) {
            var cubeGeom = new THREE.BoxGeometry(2.9, 2.9, 2.9);
            var cube = new THREE.Mesh(cubeGeom, mats);
            cube.position.set(x * 3 - 3, y * 3, z * 3 - 3);

            group.add(cube);
        }
    }
}
```